home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
476-500
/
500
/
wiconify
/
wiconify-source.lzh
/
Source
/
wMain.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-19
|
14KB
|
442 lines
/*
* WICONIFY A utility that allows you to iconify any Intuition window
* on any screen, and to open WB windows on any screen.
*
* wMain.c The handler setup and main loop routines
*
* Copyright 1990 by Davide P. Cervone, all rights reserved.
* You may use this code, provided this copyright notice is kept intact.
*/
#define INTUITION_PREFERENCES_H /* don't need 'em */
#include <intuition/intuitionbase.h>
#include "wHandler.h"
#include "wSetup.h"
#include "wMenu.h"
#include <exec/interrupts.h>
#include <devices/input.h>
#include <libraries/dos.h>
static int MessageCount; /* number of messages still not returned */
extern void wHandlerStub();
static struct Interrupt wIconInterrupt = /* the Interrupt needed to add a */
{ /* handler to the input chain */
{NULL, NULL, 0, 51, NULL}, /* ln_Pri = 51 (before Intuition) */
NULL,
&wHandlerStub /* the handler to add */
};
extern struct wMenuItem OpenWindowMenu[];
extern void cOpenScreen(),FreeAllLists();
extern void aOpenWindow(),aCloseWindow();
extern void aOpenScreen(),aCloseScreen();
extern void aSetWindowTitles(),aWindowToFront(),aWindowToBack();
extern void aActivateWindow();
extern void aBuildSysRequest(),aFreeSysRequest(),aAutoRequest();
/*
* Storage for the old library vectors that are replaced by SetFunction
*/
long OldOpenWindow,OldCloseWindow,OldOpenScreen,OldCloseScreen;
long OldSetWindowTitles,OldWindowToFront,OldWindowToBack;
long OldActivateWindow,OldBuildSysRequest,OldFreeSysRequest,OldAutoRequest;
/*
* The data needed by the loader to set up the handler
*/
static struct HandlerData HandlerData =
{
MAJVERSION,MINVERSION,
NULL, NULL,
&IntuitionBase, &GfxBase, &LayersBase, &SysBase, &DOSBase,
&wIconInterrupt,
&wMenu[0],&OpenWindowMenu[0],
&DefaultIcon, &DefaultScreenIcon,
&HiResCLICommand, &LoResCLICommand, &StackSize,
&DefaultImage, &DefaultSelect, &DefaultMask,
&DefaultScreenImage, &DefaultScreenSelect, &DefaultScreenMask,
&DefaultFlags,
&DefaultScreenFlags,
&IgnoreScreen,
&IconifyKey,&ActivateKey,
&IconifyQuals,&IconifyDisquals,&IconifyChange,
&ActivateQuals,
&Colors[0],
&cOpenScreen,&FreeAllLists,
&aOpenWindow,&OldOpenWindow,
&aCloseWindow,&OldCloseWindow,
&aOpenScreen,&OldOpenScreen,
&aCloseScreen,&OldCloseScreen,
&aSetWindowTitles,&OldSetWindowTitles,
&aWindowToFront,&OldWindowToFront,
&aWindowToBack,&OldWindowToBack,
&aActivateWindow,&OldActivateWindow,
&aBuildSysRequest,&OldBuildSysRequest,
&aFreeSysRequest,&OldFreeSysRequest,
&aAutoRequest,&OldAutoRequest
};
extern struct MsgPort *CreatePort();
extern void DeletePort();
extern void wMain();
extern void ReplyMessages();
/*
* Setup()
*
* This routine MUST be linked into the handler as the first routine.
* It is called by the loader to check version numbers, and to get
* the handler data structure. It should compare the version number
* and return NULL if a mismatch occurs or a pointer to HandlerData
* if all is OK.
*
* Since the handler is started as a process, it will also be called
* as the process first starts up. FirstCall is used to tell which
* invocation this is.
*
* When it is called as part of the process starting up
* Get our task pointer for use by the handler routines
* Create a port for icon messages
* And one for the window's common UserPort
* Get a signal for when the last window on a screen is closed
* If all of these were allocated
* Clear the close signal
* If the Real WB is open and we have a backdrop window on it
* Set and clear the menu strip (to get the NL-Deamon to change
* its pen number, in case it is going to)
* Signal the loader that all is OK so far
* Wait for the loader to finish setting up
* If we were not cancelled, call the main loop routine
* Get ready to singal OK
* Otherwise (something could not be set up) Get ready to signal CANCEL
* Reply to any messages in the UserPort or IconPort
* Free the ports that were allocated
* Signal the loader (either OK or CANCEL)
*/
struct HandlerData *Setup(MajLoadVers,MinLoadVers)
int MajLoadVers,MinLoadVers;
{
ULONG theSignal;
static int FirstCall = TRUE;
struct HandlerData *theData = &HandlerData;
if (FirstCall)
{
if (MajLoadVers < MAJLOADVERS ||
(MajLoadVers == MAJLOADVERS && MinLoadVers < MINLOADVERS))
theData = NULL;
FirstCall = FALSE;
} else {
theData = NULL;
IconTask = FindTask(NULL);
wIconPort = CreatePort(WICONPORT);
wUserPort = CreatePort(NULL);
CloseSigBit = AllocSignal(-ONE);
if (wIconPort && wUserPort && CloseSigBit != -ONE)
{
CloseSignal = (ONE << CloseSigBit);
SetSignal(CloseSignal,0L);
if (RealWB && RealWB->BackDrop)
{
SetMenuStrip(RealWB->BackDrop,wMenu); /* for NL-Deamon */
ClearMenuStrip(RealWB->BackDrop);
}
Signal(HandlerData.ParentTask,OKSIGNAL);
theSignal = Wait(OKSIGNAL| CANCELSIGNAL);
if ((theSignal & CANCELSIGNAL) == FALSE) wMain();
theSignal = OKSIGNAL;
} else theSignal = CANCELSIGNAL;
Forbid();
ReplyMessages();
if (wIconPort) DeletePort(wIconPort);
if (wUserPort) DeletePort(wUserPort);
Signal(HandlerData.ParentTask,theSignal);
}
return(theData);
}
/*
* CreatePort()
*
* Get a new port structure
* Allocate a signal for it
* If none could be allocated
* Free the structure
* Otherwise
* Set the port's name and type
* Set its signal type and signal task
* Add it to the port list if it has a name, otheriwse
* initialize its message list
*/
struct MsgPort *CreatePort(theName)
char *theName;
{
struct MsgPort *thePort;
if (NEWSTRUCT(MsgPort,thePort))
{
thePort->mp_SigBit = AllocSignal(-ONE);
if (thePort->mp_SigBit == -ONE)
{
FREESTRUCT(MsgPort,thePort);
thePort = NULL;
} else {
thePort->mp_Node.ln_Name = theName;
thePort->mp_Node.ln_Type = NT_MESSAGE;
thePort->mp_Flags = PA_SIGNAL;
thePort->mp_SigTask = (struct Task *)FindTask(NULL);
if (theName) AddPort(thePort); else NewList(&(thePort->mp_MsgList));
}
}
return(thePort);
}
/*
* DeletePort()
*
* If the port exists
* If it has a name, remove it frlom the system port list
* Remove its type and message list
* Free the port's signal
* Free the ports memory
*/
void DeletePort(thePort)
struct MsgPort *thePort;
{
if (thePort)
{
if (thePort->mp_Node.ln_Name) RemPort(thePort);
thePort->mp_Node.ln_Type = 0xFF;
thePort->mp_MsgList.lh_Head = (struct Node *)-1L;
FreeSignal(thePort->mp_SigBit);
FREESTRUCT(MsgPort,thePort);
}
}
/*
* ReportEvent()
*
* If the icon has an IconPort to send messages to
* Get a new message structure
* Increment the number of messages yet to be replied
* Set the message's Window, Icon, Action and Flags fields
* Set up the data field for special cases
* Set the reply port to the IconPort and send the message
*/
void ReportEvent(theEvent,theIcon,theData)
ULONG theEvent;
WICONREF *theIcon;
APTR theData;
{
struct wIconMessage *theMessage;
if (theIcon->Icon.IconPort)
{
if (NEWSTRUCT(wIconMessage,theMessage))
{
MessageCount++;
theMessage->Window = theIcon->Window;
theMessage->Icon = theIcon;
theMessage->Action = theEvent;
theMessage->Flags = WI_ICONMESSAGE| WI_REPORT| WI_NOREPLY;
switch(theEvent)
{
case WI_REPORTACTIVATE:
case WI_REPORTINACTIVE:
case WI_REPORTNEWSCREEN:
case WI_REPORTSCREENCLOSE:
case WI_REPORTICONEND:
theMessage->Data.DataPtr = theData;
break;
case WI_REPORTICONVERIFY:
theMessage->Flags &= ~WI_ICONMESSAGE;
break;
case WI_REPORTMOVED:
theMessage->Data.Position.x = theIcon->Icon.x;
theMessage->Data.Position.y = theIcon->Icon.y;
break;
}
theMessage->Message.mn_ReplyPort = wIconPort;
theMessage->Message.mn_Length = sizeof(struct wIconMessage);
PutMsg(theIcon->Icon.IconPort,theMessage);
}
}
}
/*
* ReportMulti()
*
* If a screen was specified, use it, otherwise start at the top of the list
* While there are more screens to check
* For each icon on the screen
* If the icon wants to hear about this type of event, report it
* If a screen was specified, we're done, otherwise go on to the next one
*/
void ReportMulti(theEvent,theData,IconScreen)
ULONG theEvent;
APTR theData;
WSCREEN *IconScreen;
{
WSCREEN *theScreen;
WICONREF *theIcon,*nextIcon;
Forbid();
if (IconScreen) theScreen = IconScreen; else theScreen = FirstScreen;
while (theScreen)
{
theIcon = theScreen->IconRef;
while (theIcon)
{
nextIcon = theIcon->Next;
if (theIcon->Icon.Report & theEvent)
ReportEvent(theEvent,theIcon,theData);
theIcon = nextIcon;
}
if (IconScreen) theScreen = NULL; else theScreen = theScreen->Next;
}
Permit();
}
/*
* wMain()
*
* Set the Wait signal bits to CANCEL, close and the bits used by the ports
* While there is more to do
* Don't try to end wIconify yet
* Wait for one of the signals we're interested in
* While there are messages in the common wIconify window UserPort
* If the message type is CLOSEWINDOW ro NEWSIZE (fake messages
* sent to Intuition windows by wIconify), then just free the message
* Otherwise
* Make a copy of the message data and reply the original
* Do the event, and record whether we are supposed to end wIconify
* While ther are messages in the IconPort (from the handler or IconCalls)
* If the message is not an IconMessage being returned to us
* Do what the message wants, and record if we are supposed to end
* If the message is not supposed to be replied (it came from us)
* If the message is a REPORT message we generated, decrement the count
* If we are trying to end and there are no more outstanding messages
* that need to be returned, go ahead and try to end
* Free the message
* Otherwise reply to the message (it's from IconCalls)
* If the last window on a screen was closed, update the menus
* If the loader wants us to end, try to quit
* Do any pending mouse moves (since we're about to Wait anyway)
* Refresh the screens that need it
* If we are supposed to end
* Try to close all screens and windows
* If all are closed, make sure there are no outstanding messages
* that need to be replied first; if not, go ahead and quit
*/
static void wMain()
{
int NotDone = TRUE;
int EndItAll;
ULONG WaitSignal = CANCELSIGNAL| CloseSignal;
ULONG theSignal;
struct IntuiMessage *inMessage,tmpMessage;
struct wIconMessage *wiMessage;
extern struct Node *GetMsg();
if (wUserPort) WaitSignal |= (ONE << wUserPort->mp_SigBit);
if (wIconPort) WaitSignal |= (ONE << wIconPort->mp_SigBit);
while (NotDone)
{
EndItAll = FALSE;
theSignal = Wait(WaitSignal | EndSignal);
while (inMessage = (struct IntuiMessage *)GetMsg(wUserPort))
{
if (inMessage->Class & FREECLASS)
{
FREESTRUCT(IntuiMessage,inMessage);
} else {
tmpMessage = *inMessage; ReplyMsg(inMessage);
EndItAll = DoEvent(&tmpMessage,EndItAll);
}
}
while (wiMessage = (struct wIconMessage *)GetMsg(wIconPort))
{
if ((wiMessage->Flags & WI_ICONMESSAGE) == 0)
EndItAll = DoIconEvent(wiMessage,EndItAll);
if (wiMessage->Flags & WI_NOREPLY)
{
if (wiMessage->Flags & WI_REPORT) MessageCount--;
if (EndSignal && MessageCount == 0) EndItAll = TRUE;
FREESTRUCT(wIconMessage,wiMessage);
} else {
ReplyMsg(wiMessage);
}
}
if (theSignal & CloseSignal) UpdateActiveMenu();
if (theSignal & EndSignal) EndItAll = TRUE;
DoMouseMove();
RefreshScreens();
if (EndItAll)
if (AttemptQuit())
if (MessageCount == 0) NotDone = FALSE;
}
}
/*
* ReplyMessages()
*
* While there are more IntuiMessages in the UserPort
* If the message is to be freed, do so, otherwise reply to it
* While there are more IconMessages in the IconPort
* If the message is not to be replied, free it, otherwise reply to it
*/
static void ReplyMessages()
{
struct IntuiMessage *inMessage;
struct wIconMessage *wiMessage;
extern struct Node *GetMsg();
while (inMessage = (struct IntuiMessage *)GetMsg(wUserPort))
{
if (inMessage->Class & FREECLASS) FREESTRUCT(IntuiMessage,inMessage);
else ReplyMsg(inMessage);
}
while (wiMessage = (struct wIconMessage *)GetMsg(wIconPort))
{
if (wiMessage->Flags & WI_NOREPLY) FREESTRUCT(wIconMessage,wiMessage);
else wiMessage->Icon = NULL, ReplyMsg(wiMessage);
}
}
/*
* AttemptEnd()
*
* This routine is called when an ENDICONIFY message arrives.
* Return a pointer to the HandlerData for use by the loader
* Get the loader's task pointer from the message data pointer
*/
void AttemptEnd(theMessage)
struct wIconMessage *theMessage;
{
theMessage->Icon = (WICONREF *) &HandlerData;
HandlerData.ParentTask = theMessage->Data.DataPtr;
}